﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Tools.Development.CopySourceAsHtml.UnitTests
{

    /// <summary>
    /// Unit tests for the <see cref="RtfReader"/> class.
    /// </summary>
    [TestClass]
    public class RtfReaderFixture
    {
        #region Inner Classes and Types

        /// <summary>
        /// Base class for all test implementations of <see cref="RtfReader"/>.
        /// </summary>
        private abstract class TestRtfReaderBase : RtfReader
        {
            protected internal override void ReadColorTableEntry(int colorId, Color color)
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadForegroundColor(int colorId)
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadBackgroundColor(int colorId)
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadBold(bool bold)
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadBeginGroup()
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadEndGroup()
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadCharacter(char c)
            {
                throw new NotImplementedException();
            }

            protected internal override void ReadNewLine()
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Implementation of <see cref="RtfReader"/> used for parsing tests.
        /// </summary>
        private class TestRtfReader_ParsingTests : TestRtfReaderBase
        {

            public abstract class ParseCallBase
            {
            }

            public class ControlWordCall : ParseCallBase
            {
                public string Rtf { get; set; }
                public int NextCharacterIndex { get; set; }
                public string ControlWord { get; set; }
                public bool HasParameter { get; set; }
                public long ParameterValue { get; set; }
                public int Result { get; set; }
            }

            public class ControlSymbolCall : ParseCallBase
            {
                public string Rtf { get; set; }
                public int NextCharacterIndex { get; set; }
                public char ControlSymbol { get; set; }
                public int Result { get; set; }
            }

            public class BeginGroupCall : ParseCallBase
            {
            }

            public class EndGroupCall : ParseCallBase
            {
            }

            public class CharacterCall : ParseCallBase
            {
                public char Character { get; set; }
            }

            private Queue<TestRtfReader_ParsingTests.ParseCallBase> _expectedCalls;

            public TestRtfReader_ParsingTests(Queue<TestRtfReader_ParsingTests.ParseCallBase> expectedCalls)
            {
                _expectedCalls = expectedCalls;
            }

            protected override int ParseControlWord(string rtf, int nextCharacterIndex, int lastCharacterIndex, string controlWord, bool hasParameter, long parameterValue)
            {
                ControlWordCall call;

                Assert.IsTrue(_expectedCalls.Count > 0);
                call = _expectedCalls.Dequeue() as ControlWordCall;
                Assert.IsNotNull(call);
                Assert.AreEqual(call.Rtf, rtf);
                Assert.AreEqual(call.NextCharacterIndex, nextCharacterIndex);
                Assert.AreEqual(call.ControlWord, controlWord);
                Assert.AreEqual(call.HasParameter, hasParameter);
                Assert.AreEqual(call.ParameterValue, parameterValue);
                return call.Result;
            }

            protected override int ParseControlSymbol(string rtf, int nextCharacterIndex, int lastCharacterIndex, char controlSymbol)
            {
                ControlSymbolCall call;

                Assert.IsTrue(_expectedCalls.Count > 0);
                call = _expectedCalls.Dequeue() as ControlSymbolCall;
                Assert.IsNotNull(call);
                Assert.AreEqual(call.Rtf, rtf);
                Assert.AreEqual(call.NextCharacterIndex, nextCharacterIndex);
                Assert.AreEqual(call.ControlSymbol, controlSymbol);
                return call.Result;
            }

            protected internal override void ReadBeginGroup()
            {
                BeginGroupCall call;

                Assert.IsTrue(_expectedCalls.Count > 0);
                call = _expectedCalls.Dequeue() as BeginGroupCall;
                Assert.IsNotNull(call);
            }

            protected internal override void ReadEndGroup()
            {
                EndGroupCall call;

                Assert.IsTrue(_expectedCalls.Count > 0);
                call = _expectedCalls.Dequeue() as EndGroupCall;
                Assert.IsNotNull(call);
            }

            protected internal override void ReadCharacter(char c)
            {
                CharacterCall call;

                Assert.IsTrue(_expectedCalls.Count > 0);
                call = _expectedCalls.Dequeue() as CharacterCall;
                Assert.IsNotNull(call);
                Assert.AreEqual(call.Character, c);
            }

        }

        /// <summary>
        /// Implementation of <see cref="RtfReader"/> used for character tests.
        /// </summary>
        private class TestRtfReader_CharacterTests : TestRtfReaderBase
        {

            private StringBuilder _characters;

            public TestRtfReader_CharacterTests()
            {
                _characters = new StringBuilder();
            }

            public string Characters
            {
                get { return _characters.ToString(); }
            }

            protected internal override void ReadCharacter(char c)
            {
                _characters.Append(c);
            }

        }

        /// <summary>
        /// Implementation of <see cref="RtfReader"/> used for formatting tests.
        /// </summary>
        private class TestRtfReader_FormattingTests : TestRtfReaderBase
        {

            private StringBuilder _sequence;

            public TestRtfReader_FormattingTests()
            {
                _sequence = new StringBuilder();
            }

            public string Sequence
            {
                get { return _sequence.ToString(); }
            }

            protected internal override void ReadCharacter(char c)
            {
                if (c == '\t')
                {
                    _sequence.Append("(tab)");
                }
                else
                {
                    _sequence.Append(c);
                }
            }

            protected internal override void ReadNewLine()
            {
                _sequence.Append("(newline)");
            }

            protected internal override void ReadForegroundColor(int colorId)
            {
                _sequence.Append(String.Format(CultureInfo.InvariantCulture, "(foreground color {0})", colorId));
            }

            protected internal override void ReadBackgroundColor(int colorId)
            {
                _sequence.Append(String.Format(CultureInfo.InvariantCulture, "(background color {0})", colorId));
            }

            protected internal override void ReadBold(bool bold)
            {
                if (bold)
                {
                    _sequence.Append("(begin bold)");
                }
                else
                {
                    _sequence.Append("(end bold)");
                }
            }

        }

        /// <summary>
        /// Implementation of <see cref="RtfReader"/> used for font table tests.
        /// </summary>
        private class TestRtfReader_FontTableTests : TestRtfReaderBase
        {

            private StringBuilder _characters;

            public TestRtfReader_FontTableTests()
            {
                _characters = new StringBuilder();
            }

            public string Characters
            {
                get { return _characters.ToString(); }
            }

            protected internal override void ReadCharacter(char c)
            {
                _characters.Append(c);
            }

            protected internal override void ReadBeginGroup()
            {
            }

            protected internal override void ReadEndGroup()
            {
            }

        }

        /// <summary>
        /// Implementation of <see cref="RtfReader"/> used for color table tests.
        /// </summary>
        private class TestRtfReader_ColorTableTests : TestRtfReaderBase
        {

            public class ColorTableEntry
            {
                public int ColorId { get; set; }
                public Color Color { get; set; }
            }

            private Queue<ColorTableEntry> _expectedColorTableEntries;
            private StringBuilder _characters;

            public TestRtfReader_ColorTableTests(Queue<ColorTableEntry> expectedColorTableEntries)
            {
                _expectedColorTableEntries = expectedColorTableEntries;
                _characters = new StringBuilder();
            }

            public string Characters
            {
                get { return _characters.ToString(); }
            }

            protected internal override void ReadColorTableEntry(int colorId, Color color)
            {
                ColorTableEntry entry;

                Assert.IsTrue(_expectedColorTableEntries.Count > 0);
                entry = _expectedColorTableEntries.Dequeue();
                Assert.AreEqual(entry.ColorId, colorId);
                Assert.AreEqual(entry.Color, color);
            }

            protected internal override void ReadCharacter(char c)
            {
                _characters.Append(c);
            }

            protected internal override void ReadBeginGroup()
            {
            }

            protected internal override void ReadEndGroup()
            {
            }

        }

        #endregion // Inner Classes and Types

        #region Methods

        #region Read

        #region Parsing Tests

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> throws <see cref="ArgumentNullException"/> 
        /// when called with a <see langword="null"/> value.
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void TestReadWithNullValue()
        {
            TestRtfReader_ParsingTests reader;

            reader = new TestRtfReader_ParsingTests(new Queue<TestRtfReader_ParsingTests.ParseCallBase>());
            reader.Read(null);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> does nothing when called with an empty value.
        /// </summary>
        [TestMethod]
        public void TestReadWithEmptyValue()
        {
            TestRtfReader_ParsingTests reader;

            reader = new TestRtfReader_ParsingTests(new Queue<TestRtfReader_ParsingTests.ParseCallBase>());
            reader.Read("");
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> does nothing when called with an empty group.
        /// </summary>
        [TestMethod]
        public void TestReadWithEmptyGroup()
        {
            TestRtfReader_ParsingTests reader;

            reader = new TestRtfReader_ParsingTests(new Queue<TestRtfReader_ParsingTests.ParseCallBase>());
            reader.Read("{}");
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses control words without parameters
        /// successfully.
        /// </summary>
        [TestMethod]
        public void TestReadWithControlWordWithoutParameter()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\testA}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 7, ControlWord = "testA", HasParameter = false, ParameterValue = 0, Result = 0 },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses control words with positive parameters 
        /// successfully.
        /// </summary>
        [TestMethod]
        public void TestReadWithControlWordWithPositiveParameter()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\testA1}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 8, ControlWord = "testA", HasParameter = true, ParameterValue = 1, Result = 0 },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses control words with negative parameters 
        /// successfully.
        /// </summary>
        [TestMethod]
        public void TestReadWithControlWordWithNegativeParameter()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\testA-1}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 9, ControlWord = "testA", HasParameter = true, ParameterValue = -1, Result = 0 },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses control word sequences successfully.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This test ensures behavior for 6 control words with combinations of parameters (no 
        /// parameter, positive parameter, negative parameter) and separators (no separator, 
        /// separator).
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithControlWordSequence()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\testA\testB \testC1\testD2 \testE-3\testF-4 }";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 7, ControlWord = "testA", HasParameter = false, ParameterValue = 0, Result = 0 }, // no parameter, no separator
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 14, ControlWord = "testB", HasParameter = false, ParameterValue = 0, Result = 0 }, // no parameter, separator
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 21, ControlWord = "testC", HasParameter = true, ParameterValue = 1, Result = 0 }, // positive parameter, no separator
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 29, ControlWord = "testD", HasParameter = true, ParameterValue = 2, Result = 0 }, // positive parameter, separator
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 37, ControlWord = "testE", HasParameter = true, ParameterValue = -3, Result = 0 }, // negative parameter, no separator
                new TestRtfReader_ParsingTests.ControlWordCall { Rtf = rtf, NextCharacterIndex = 46, ControlWord = "testF", HasParameter = true, ParameterValue = -4, Result = 0 }, // positive parameter, separator
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses control symbols successfully.
        /// </summary>
        [TestMethod]
        public void TestReadWithControlSymbol()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\~}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.ControlSymbolCall { Rtf = rtf, NextCharacterIndex = 3, ControlSymbol = '~', Result = 0 },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses control symbol sequences.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This test ensures behavior for 3 control sequences with different following characters
        /// (\, whitespace, literal text).
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithControlSymbolSequence()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{\~\- \_T}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new TestRtfReader_ParsingTests.ParseCallBase[]
            {
                new TestRtfReader_ParsingTests.ControlSymbolCall { Rtf = rtf, NextCharacterIndex = 3, ControlSymbol = '~', Result = 0 }, // followed by \
                new TestRtfReader_ParsingTests.ControlSymbolCall { Rtf = rtf, NextCharacterIndex = 5, ControlSymbol = '-', Result = 0 }, // followed by whitespace
                new TestRtfReader_ParsingTests.CharacterCall { Character = ' ' },
                new TestRtfReader_ParsingTests.ControlSymbolCall { Rtf = rtf, NextCharacterIndex = 8, ControlSymbol = '_', Result = 0 }, // followed by literal text
                new TestRtfReader_ParsingTests.CharacterCall { Character = 'T' },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses groups.
        /// </summary>
        [TestMethod]
        public void TestReadWithGroups()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = @"{{}}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new TestRtfReader_ParsingTests.ParseCallBase[]
            {
                new TestRtfReader_ParsingTests.BeginGroupCall(),
                new TestRtfReader_ParsingTests.EndGroupCall(),
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly ignores CR and LF characters.
        /// </summary>
		[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Cr")]
		[SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Lf")]
		[TestMethod]
        public void TestReadWithCrLf()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = "{\r\r\n\n}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>();
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> parses literal text.
        /// </summary>
        [TestMethod]
        public void TestReadWithLiteralText()
        {
            string rtf;
            Queue<TestRtfReader_ParsingTests.ParseCallBase> script;
            TestRtfReader_ParsingTests reader;

            rtf = "{T}";
            script = new Queue<TestRtfReader_ParsingTests.ParseCallBase>(new[]
            {
                new TestRtfReader_ParsingTests.CharacterCall { Character = 'T' },
            });
            reader = new TestRtfReader_ParsingTests(script);
            reader.Read(rtf);
        }

        #endregion // Parsing Tests

        #region Character Tests

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses 8-bit characters represented 
        /// as 2 hexadecimal characters (\'xx) in the specified encoding.
        /// </summary>
        [TestMethod]
        public void TestReadWith2Digit8BitCharacters()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            rtf = @"{\ansicpg1252\'54\'65\'73\'74}"; // NOTE: We need to specify the encoding used.
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses 8-bit characters represented 
        /// as 1 hexadecimal character (\'x) in the specified encoding.
        /// </summary>
        [TestMethod]
        public void TestReadWith1Digit8BitCharacters()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            rtf = @"{\ansicpg1252\'d\'a}"; // NOTE: We need to specify the encoding used.
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual("\r\n", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the 8-bit character 
        /// \'0 as a space.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This is a special case.  \'0 doesn't appear to be a part of the RTF standard, but 
        /// Visual Studio will generate it, and the most logical behavior in those circumstances 
        /// appears to be to parse it as a space.
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWith1Digit8BitCharacterZero()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            rtf = @"{\'0}";
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual(" ", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses escaped characters 
        /// (\\, \{, \}).
        /// </summary>
        [TestMethod]
        public void TestReadWithEscapedCharacters()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            rtf = @"{\\\{\}}";
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual(@"\{}", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly ignores unsupported escaped 
        /// characters (\*, etc).
        /// </summary>
        [TestMethod]
        public void TestReadWithUnsupportedEscapedCharacters()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            rtf = @"{\*}";
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual("", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses Unicode characters (\uXC).
        /// </summary>
        [TestMethod]
        public void TestReadWithUnicodeCharacters()
        {
            string rtf;
            TestRtfReader_CharacterTests reader;

            // NOTE: Each Unicode value is followed by a corresponding ANSI value.  In this test, 
            // all of the ANSI values are 'X', so that we know the value returned is coming from
            // the Unicode values and not the ANSI values.
            rtf = @"{\u84X\u101X\u115X\u116X}";
            reader = new TestRtfReader_CharacterTests();
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        #endregion // Character Tests

        #region Formatting Tests

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> hides ignored or unknown control words.
        /// </summary>
        /// <remarks>
        /// <para>
        /// This isn't really a formatting test, but I'm not sure where else to put it.
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithIgnoredOrUnknownControlWords()
        {
            string rtf;
            TestRtfReader_FormattingTests reader;

            rtf = @"{\rtf1\ansi\mac Test}"; // NOTE: None of these 3 control words should have any effect on formatting.
            reader = new TestRtfReader_FormattingTests();
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Sequence);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> reads bold and unbold commands correctly.
        /// </summary>
		[TestMethod]
        public void TestReadWithBoldUnbold()
        {
            string rtf;
            TestRtfReader_FormattingTests reader;

            rtf = @"{Unbold\b Bold\b0 Unbold}";
            reader = new TestRtfReader_FormattingTests();
            reader.Read(rtf);

            Assert.AreEqual("Unbold(begin bold)Bold(end bold)Unbold", reader.Sequence);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> reads foreground and background color commands 
        /// correctly.
        /// </summary>
        [TestMethod]
        public void TestReadWithForegroundAndBackgroundColors()
        {
            string rtf;
            TestRtfReader_FormattingTests reader;

            rtf = @"{Default\cf1 Foreground1\cb1 Background1\cf2 Foreground2\cb2 Background2}";
            reader = new TestRtfReader_FormattingTests();
            reader.Read(rtf);

            Assert.AreEqual("Default(foreground color 1)Foreground1(background color 1)Background1(foreground color 2)Foreground2(background color 2)Background2", reader.Sequence);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> reads tab commands correctly.
        /// </summary>
        [TestMethod]
        public void TestReadWithTabs()
        {
            string rtf;
            TestRtfReader_FormattingTests reader;

            rtf = @"{Column1\tab Column2\tab Column3}";
            reader = new TestRtfReader_FormattingTests();
            reader.Read(rtf);

            Assert.AreEqual("Column1(tab)Column2(tab)Column3", reader.Sequence);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> reads newline commands correctly.
        /// </summary>
        [TestMethod]
        public void TestReadWithNewLines()
        {
            string rtf;
            TestRtfReader_FormattingTests reader;

            rtf = @"{Line1\par Line2\par Line3}";
            reader = new TestRtfReader_FormattingTests();
            reader.Read(rtf);

            Assert.AreEqual("Line1(newline)Line2(newline)Line3", reader.Sequence);
        }

        #endregion // Formatting Tests

        #region Font Table Tests

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the font table when it 
        /// contains a single font.
        /// </summary>
        /// <remarks>
        /// <para>
        /// We don't currently use the font table for anything, but we need to get rid of it so 
        /// that we can get the _content after it.  This test ensures that we get rid of the font
        /// table without getting rid of the _content after it.
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithFontTableSingleFont()
        {
            string rtf;
            TestRtfReader_FontTableTests reader;

            rtf = @"{{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}Test}";
            reader = new TestRtfReader_FontTableTests();
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the font table when it 
        /// contains multiple fonts.
        /// </summary>
        /// <remarks>
        /// <para>
        /// We don't currently use the font table for anything, but we need to get rid of it so 
        /// that we can get the _content after it.  This test ensures that we get rid of the font
        /// table without getting rid of the _content after it.
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithFontTableMultipleFonts()
        {
            string rtf;
            TestRtfReader_FontTableTests reader;

            rtf = @"{{\fonttbl{\f0\fnil\fcharset0\fprq0 Courier New;}{\f1\fnil\fcharset0\fprq0 Consolas;}}Test}";
            reader = new TestRtfReader_FontTableTests();
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the font table when the font
        /// table is the only _content.
        /// </summary>
        /// <remarks>
        /// <para>
        /// We don't currently use the font table for anything, but we need to get rid of it so 
        /// that we can get the _content after it.  This test ensures that we get rid of the font
        /// table without getting rid of the _content after it.
        /// </para>
        /// </remarks>
        [TestMethod]
        public void TestReadWithFontTableOnly()
        {
            string rtf;
            TestRtfReader_FontTableTests reader;

            rtf = @"{{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}}";
            reader = new TestRtfReader_FontTableTests();
            reader.Read(rtf);

            Assert.AreEqual("", reader.Characters);
        }

        #endregion // Font Table Tests

        #region Color Table Tests

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the _color table when it
        /// contains a single _color.
        /// </summary>
        [TestMethod]
        public void TestReadWithColorTableSingleColor()
        {
            Queue<TestRtfReader_ColorTableTests.ColorTableEntry> script;
            string rtf;
            TestRtfReader_ColorTableTests reader;

            rtf = @"{{\colortbl;\red0\green128\blue255;}Test}";

            script = new Queue<TestRtfReader_ColorTableTests.ColorTableEntry>(new TestRtfReader_ColorTableTests.ColorTableEntry[]
            {
                new TestRtfReader_ColorTableTests.ColorTableEntry { ColorId = 1, Color = Color.FromArgb(0, 128, 255) },
            });
            reader = new TestRtfReader_ColorTableTests(script);
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the _color table when it
        /// contains a multiple colors.
        /// </summary>
        [TestMethod]
        public void TestReadWithColorTableMultipleColors()
        {
            Queue<TestRtfReader_ColorTableTests.ColorTableEntry> script;
            string rtf;
            TestRtfReader_ColorTableTests reader;

            rtf = @"{{\colortbl;\red0\green128\blue255;\red255\green128\blue0;}Test}";

            script = new Queue<TestRtfReader_ColorTableTests.ColorTableEntry>(new TestRtfReader_ColorTableTests.ColorTableEntry[]
            {
                new TestRtfReader_ColorTableTests.ColorTableEntry { ColorId = 1, Color = Color.FromArgb(0, 128, 255) },
                new TestRtfReader_ColorTableTests.ColorTableEntry { ColorId = 2, Color = Color.FromArgb(255, 128, 0) },
            });
            reader = new TestRtfReader_ColorTableTests(script);
            reader.Read(rtf);

            Assert.AreEqual("Test", reader.Characters);
        }

        /// <summary>
        /// Ensures <see cref="RtfReader.Read"/> correctly parses the _color table when the 
        /// _color table is the only _content.
        /// </summary>
        [TestMethod]
        public void TestReadWithColorTableOnly()
        {
            Queue<TestRtfReader_ColorTableTests.ColorTableEntry> script;
            string rtf;
            TestRtfReader_ColorTableTests reader;

            rtf = @"{{\colortbl;\red0\green128\blue255;}}";

            script = new Queue<TestRtfReader_ColorTableTests.ColorTableEntry>(new TestRtfReader_ColorTableTests.ColorTableEntry[]
            {
                new TestRtfReader_ColorTableTests.ColorTableEntry { ColorId = 1, Color = Color.FromArgb(0, 128, 255) },
            });
            reader = new TestRtfReader_ColorTableTests(script);
            reader.Read(rtf);

            Assert.AreEqual("", reader.Characters);
        }

        #endregion // Color Table Tests

        #endregion // Read

        #endregion // Methods
    }
}
